package com.wsoft.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.wsoft.constant.redis.RedisKeyConstant;
import com.wsoft.core.exception.Asserts;
import com.wsoft.core.service.RedisService;
import com.wsoft.core.vo.DictCacheVO;
import com.wsoft.core.vo.DictDataCacheVO;
import com.wsoft.enums.DictTypeEnum;
import com.wsoft.service.IDictCacheService;
import com.wsoft.system.dto.TsDictDataDto;
import com.wsoft.system.entity.TsDictDataEntity;
import com.wsoft.system.entity.TsDictEntity;
import com.wsoft.system.manager.DictDataManager;
import com.wsoft.system.manager.DictManager;
import com.wsoft.system.service.ITsDictDataService;
import com.wsoft.system.service.ITsDictService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.groupingBy;

/**
 * @Author Zhang gukai
 * @Date 2024/9/11 8:57
 */
@Service
public class DictCacheServiceImpl implements IDictCacheService {
    @Resource
    private DictManager dictManager;

    @Resource
    private RedisService redisService;

    @Resource
    private DictDataManager dictDataManager;

    @Resource
    private ITsDictDataService dictDataService;

    @Resource
    private ITsDictService dictService;
    @Override
    public List<DictDataCacheVO> getDictByCode(String code) {
        Object cacheValue = redisService.get(RedisKeyConstant.DICT_CACHE + code);
        if (cacheValue instanceof List) {
            return JSONArray.parseArray(JSONObject.toJSONString(cacheValue), DictDataCacheVO.class);
        }
        else {
            //无缓存 查询数据库
            List<TsDictEntity> list = dictManager.getDictByCode(code);
            TsDictEntity dict = list.get(0);
            List<TsDictDataEntity> data = dictDataManager.getDataByDictId(dict.getId());
            List<DictDataCacheVO> collect = data.stream().map(e -> Convert.convert(DictDataCacheVO.class, e)).collect(Collectors.toList());
            if (data.size() <= 0) {
                Asserts.fail("[ts.dict.not.exist]");
            }
            //树形字典
            List<DictDataCacheVO> result = new ArrayList<>();
            if (dict.getDictType() == DictTypeEnum.TREE.getCode()) {
                List<TsDictDataDto> tree = toTree(data, 0L);
                result = tree.stream().map(s -> Convert.convert(DictDataCacheVO.class, s)).collect(Collectors.toList());
                redisService.set(RedisKeyConstant.DICT_CACHE + dict.getCode(),result);
            }
            //常规字典
            if (dict.getDictType() == DictTypeEnum.NORMAL.getCode()) {
                redisService.set(RedisKeyConstant.DICT_CACHE + dict.getCode(),collect);
                result =collect;
            }
            return result;
        }
    }

    @Override
    public List<DictCacheVO> selectAll() {
        Object cacheValue = redisService.get(RedisKeyConstant.DICT_CACHE_ALL);
        if (cacheValue instanceof List) {
            return JSONArray.parseArray(JSONObject.toJSONString(cacheValue), DictCacheVO.class);
        }
        else {
            List<TsDictEntity> dictList = dictService.list();
            List<DictCacheVO> dictDtoList = dictList.stream().map(e -> Convert.convert(DictCacheVO.class, e)).collect(Collectors.toList());
            List<TsDictDataEntity> dataList = dictDataService.list();
            Map<Long, List<TsDictDataEntity>> collect = dataList.stream()
                    .collect(groupingBy(TsDictDataEntity::getDictId));
            dictDtoList.forEach(e -> {
                if (e.getDictType() == DictTypeEnum.NORMAL.getCode()) {
                    if (CollUtil.isNotEmpty(collect.get(e.getId()))){
                        List<DictDataCacheVO> result = collect.get(e.getId()).stream().map(item -> Convert.convert(DictDataCacheVO.class, item)).collect(Collectors.toList());
                        e.setDataList(result);
                    }
                }

                if (e.getDictType() == DictTypeEnum.TREE.getCode()) {
                    if (CollUtil.isNotEmpty(collect.get(e.getId()))) {
                        List<TsDictDataDto> tree = toTree(collect.get(e.getId()), 0L);
                        List<DictDataCacheVO> treeRes = tree.stream().map(s -> Convert.convert(DictDataCacheVO.class, s)).collect(Collectors.toList());
                        e.setDataList(treeRes);
                    }
                }
            });
            redisService.set(RedisKeyConstant.DICT_CACHE_ALL, dictDtoList);
            return dictDtoList;
        }
    }

    private List<TsDictDataDto> toTree(List<TsDictDataEntity> list, Long parentId) {
        // 扁平数据
        List<TsDictDataDto> lineList = new ArrayList<>();
        for (TsDictDataEntity e : list) {
            TsDictDataDto dto = Convert.convert(TsDictDataDto.class, e);
            lineList.add(dto);
        }
        Map<String, TsDictDataDto> temp = new LinkedHashMap<>();
        Map<String, TsDictDataDto> tree = new LinkedHashMap<>();
        for (TsDictDataDto g : lineList) {
            temp.put(g.getId().toString(), g);
        }
        for (String key : temp.keySet()) {
            TsDictDataDto dictData = temp.get(key);

            if ( dictData.getPid().equals(parentId)) {
                tree.put(dictData.getId().toString(), dictData);
            } else {
                if (temp.get(dictData.getPid().toString()) == null) {
                    continue;
                }
                if (temp.get(dictData.getPid().toString()).getChildren() == null) {
                    temp.get(dictData.getPid().toString()).setChildren(new ArrayList<>());
                }
                temp.get(dictData.getPid().toString()).getChildren().add(dictData);
            }
        }
        // 树状数据
        List<TsDictDataDto> treeList = new ArrayList<>();
        for (String key : tree.keySet()) {
            treeList.add(tree.get(key));
        }
        return treeList;
    }
}
